const net = require( 'net' );
const exec = require('child_process').exec

const MongoClient = require('mongodb').MongoClient;
const url = "mongodb://localhost:27017/"

const port = 8000;
const hostname = '127.0.0.1';

// 定义两个变量， 一个用来计数，一个用来保存客户端
let clients = {};
let clientName = 0;



// 创建服务器
const server = new net.createServer();

server.on('connection', (client) => {
    client.name = ++clientName; // 给每一个client起个名
    clients[client.name] = client; // 将client保存在clients

    client.on('data', function (msg) { //接收client发来的信息
        console.log(`客户端${client.name}发来一个信息：${msg}`);
        if(msg.toString() === 'ok') {
            if(queue.length) {
                let question = queue.unshift()
                console.log("gggg", queue)
                client.write(JSON.stringify(question))
            } else {
                client.write(JSON.stringify({"id": -1}))
            }
        } else {
            //  1通过 2编译错误 3答案错误 4超时 5超内存
            const { ret, cases, id, code, file_name } = JSON.parse(msg.toString())
            if(ret === -1) {
                console.log("判题机出错！")
            } else {
                answer_store(ret, cases, id, code, file_name)
                    .then((v) => {
                        question_delete(id).then(() => {
                            console.log(`题目${v}完成判题`)
                        })
                    })
            }
        }

    });

    client.on('error', function (e) { //监听客户端异常
        console.log('client error' + e);
        client.end();
    });

    client.on( 'close', function () {
        delete clients[client.name];
        console.log(`客户端${ client.name }下线了`);
    });

});

server.listen( port,hostname,function () {
    console.log(`服务器运行在：http://${hostname}:${port}`);
});

let queue = new Array
	
main()

async function main() {
    while(1) {
        await sleep(1000)
        //v是问题
        let v = await search()
        console.log(v)
        if(v) {
            queue.push(v)
            //发现待判题就 将题目放入队列 启动容器
        }
		if(queue.length){
			execute('docker run -d -m 300M --memory-swap -1 --rm --network host  mycpp:v1 python3 main.py')

		}
        //TODO:启动容器时怎么分配测试数据呢 /在创建容器时使用 数据卷/根据file_name下载
        // if(queue) {
        //     //启动容器
        // }
    }
}

function sleep(ms) {
    return new Promise(resolve=>setTimeout(resolve, ms))
}

//TODO: 找判题的流程：寻找待判题目submits 删除 加入队列
//      问题：直接查找删除数据库；消耗时间过多；
//          判题服务器崩溃时队列中的submits会消失 数据库中state为1的数据无法处理
//      改进：消息队列

async function search() {
    //找 判题
    return await new Promise(function (resolve, reject) {
        MongoClient.connect(url, function(err, db) {
            if (err) throw err;
            let dbs = db.db("blog");
            let v
            dbs.collection("submits").find({"state": 0}).toArray(async function(err, result) { // 返回集合中所有数据
                if (err) throw err;
                //console.log(result)
                await db.close()
                if(result.length) {
                    v = result[0]
                    const id = v["id"]
                    question_update(id)
                        .then(() => {
                            resolve(v)
                        })
                } else {
                    resolve()
                }
            });

        });
    })
}

//运行cmd
function execute(cmd) {
    exec(cmd, function (error, stdout, stderr) {
        if (error) {
            console.error(error);
        } else {
            console.log("success");
        }
    });
}

//完成判题后 提交answer
async function answer_store(ret, cases, id, code, file_name) {
    // ret 1通过 2编译错误 3答案错误 4超时 5超内存
    // cases 通过案例
    // id 序列号
    // code 代码
    return new Promise(function (resolve, reject) {
        MongoClient.connect(url, function (err, db) {
            if (err) throw err;
            let dbs = db.db("blog");
            const echo = {ret, cases, id, code, file_name, "time": new Date().getTime()};
            dbs.collection("answers").insertOne(echo, function (err, res) {
                if (err) throw err;
                console.log("文档插入成功");
                db.close();
                resolve(res.insertedId)
            });
        });
    })
}

//完成判题后 删除数据库中的正在判题记录
async function question_delete(id) {
    return new Promise(function (resolve, reject) {
        MongoClient.connect(url, async function (err, db) {
            if (err) throw err;
            let dbs = db.db("blog");
            const whereStr = { "id": id};  // 查询条件
            await dbs.collection("submits").deleteOne(whereStr, function(err, res) {
                if (err) throw err;
                console.log("文档删除成功");
                db.close()
                resolve()
            })
        });
    })
}

//将数据库中的 state为0的等待判题的记录改为state为1的正在判题
async function question_update(id) {
    return new Promise(function (resolve, reject) {
        MongoClient.connect(url, function(err, db) {
            if (err) throw err;
            let dbo = db.db("blog");
            const whereStr = {"id": id};  // 查询条件
            const updateStr = {$set: { "state" : 1 }};
            dbo.collection("submits").updateOne(whereStr, updateStr, function(err, res) {
                if (err) throw err;
                console.log("文档更新成功");
                db.close();
                resolve();
            });
        });
    })
}